/**
 * My simple header template from child directory
 * ConcurrentExecutor.java - ${projectName} - ${organizationName} - ${inceptionYear}
 */
package FourthTry.concurrent;

/*
 * #%L
 * Ability-tester
 * %%
 * Copyright (C) 2014 AmazingSERKU
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */


import FourthTry.Coordinates;
import org.apache.log4j.Logger;

import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CyclicBarrier;

/**
 * Created with IntelliJ IDEA.
 * User: Gauss
 * Date: 21.01.14
 * Time: 21:39
 * To change this template use File | Settings | File Templates.
 */
public class ConcurrentExecutor {

    private static Logger logger = Logger.getLogger(ConcurrentExecutor.class);
    private Map<Coordinates, ConflictCell> conflictCells;
    private List<ConcurrentTreasureHunter> hunters;
    private CyclicBarrier barrier;

    public ConcurrentExecutor(ArrayList<ConcurrentTreasureHunter> hunters) {
        this.hunters = new CopyOnWriteArrayList<ConcurrentTreasureHunter>(hunters);
        this.barrier = new CyclicBarrier(hunters.size() + 1);
        this.conflictCells = new HashMap<Coordinates, ConflictCell>();
    }

    public void startTreasureHunting() {
        ThreadGroup group = initializeThreads();
        while (group.activeCount()!=0) {
            if (barrier.getNumberWaiting() == hunters.size()) {
                resolveConflicts();
                for (int i=0; i<hunters.size(); i++) {
                    logger.info("hunter#" + i + " on " + hunters.get(i).getCoordinates().toString() + " ");
                }
                barrier.reset();
            }
        }
    }

    private ThreadGroup initializeThreads() {
        ThreadGroup group = new ThreadGroup("hunters");
        for (ConcurrentTreasureHunter hunter: hunters) {
            hunter.setBarrier(barrier);
            hunter.setExecutor(this);
            new Thread(group, hunter).start();
        }
        return group;
    }

    private void resolveConflicts() {
        for (ConcurrentTreasureHunter hunter: hunters) {
            ConflictCell cell = new ConflictCell(hunter, hunter.getCell().getCoordinates());
            addCellToMap(hunter, cell);
        }
        for (ConflictCell cell: conflictCells.values()) {
            cell.resolveTargets();
        }
    }

    private void addCellToMap(ConcurrentTreasureHunter hunter, ConflictCell cell) {
        ConflictCell temp = conflictCells.get(cell.getCoordinates());
        if (temp == null) {
            conflictCells.put(cell.getCoordinates(), cell);
        } else {
            temp.addHunter(hunter);
        }
    }

    public void removeHunter(ConcurrentTreasureHunter hunter) {
        hunters.remove(hunter);
    }
}
